package cn.edu.sjtu.stap.graph;

/**
 * This is the edge in a graph.
 * 
 * @author William
 * 
 */
public class GraphEdge extends GraphComponent {
    private static final long serialVersionUID = 1L;

    protected long id;

    protected String note;

    /**
     * The source node from which this edge leaves.
     */
    protected GraphNode sourceNode;

    /**
     * The destination node to which this edge enters.
     */
    protected GraphNode destinationNode;

    /**
     * Swap the contents of the two edges.
     * 
     * @param e1
     *            The first edge.
     * @param e2
     *            The second edge.
     */
    public static void swap(GraphEdge e1, GraphEdge e2) {
        long tmpId = e1.id;
        String tmpNote = e1.note;
        GraphNode tmpSourceNode = e1.sourceNode;
        GraphNode tmpDestinationNode = e1.destinationNode;

        e1.id = e2.id;
        e1.note = e2.note;
        e1.sourceNode = e2.sourceNode;
        e1.destinationNode = e2.destinationNode;

        e2.id = tmpId;
        e2.note = tmpNote;
        e2.sourceNode = tmpSourceNode;
        e2.destinationNode = tmpDestinationNode;
    }

    /**
     * Construct this edge with the given id, and set source and destination
     * nodes.
     * 
     * @param id
     *            The id of this edge.
     * @param sourceNode
     *            The source node of this edge.
     * @param destinationNode
     *            The destination node of this edge.
     */
    public GraphEdge(long id, GraphNode sourceNode, GraphNode destinationNode) {
        this(id, null, sourceNode, destinationNode);
    }

    /**
     * Construct this edge with id and some notes.
     * 
     * @param id
     *            The id of this edge.
     * @param s
     *            The notes for this edge.
     * @param sourceNode
     *            The source node of this edge.
     * @param destinationNode
     *            The destination node of this edge.
     */
    public GraphEdge(long id, String s, GraphNode sourceNode,
            GraphNode destinationNode) {
        if (sourceNode == null || destinationNode == null) {
            throw new NullPointerException();
        }

        this.id = id;
        this.note = s;

        this.sourceNode = sourceNode;
        this.destinationNode = destinationNode;
        sourceNode.addOutgoingEdge(this);
        destinationNode.addIncomingEdge(this);
    }

    protected GraphEdge(long id) {
        this.id = id;
    }

    /**
     * Get the id of this edge.
     * 
     * @return id of this edge.
     */
    public long getId() {
        return id;
    }

    /**
     * Get notes for this edge.
     * 
     * @return notes for this edge.
     */
    public String getNote() {
        return note;
    }

    /**
     * Set notes for this edge.
     * 
     * @param s
     *            The notes to set for this edge.
     */
    public void setNote(String s) {
        this.note = s;
    }

    /**
     * Get the node which this edge leaves.
     * 
     * @return the node which this edge leaves.
     */
    public GraphNode getSourceNode() {
        return sourceNode;
    }

    /**
     * Set the node which this edge leaves. It first cuts the relationship
     * between this edge and the original source node, then it builds the
     * relationship between this node and the given source node.
     * 
     * @param node
     *            The source node that this edge leaves.
     * @throws NullPointerException
     *             if the given node is null.
     */
    public void setSourceNode(GraphNode node) {
        if (null == node) {
            throw new NullPointerException();
        }

        if (sourceNode != null) {
            sourceNode.removeOutgoingEdge(this);
        }
        sourceNode = node;
        sourceNode.addOutgoingEdge(this);
    }

    /**
     * Get the node which this edge enters.
     * 
     * @return the node which this edge enters.
     */
    public GraphNode getDestinationNode() {
        return destinationNode;
    }

    /**
     * Set the node which this edge enters. It first cuts the relationship
     * between this edge and the original destination node, then it builds the
     * relationship between this node and the given destination node.
     * 
     * @param node
     *            The destination node that this edge enters.
     * @throws NullPointerException
     *             if the given node is null.
     */
    public void setDestinationNode(GraphNode node) {
        if (null == node) {
            throw new NullPointerException();
        }

        if (destinationNode != null) {
            destinationNode.removeIncomingEdge(this);
        }
        destinationNode = node;
        destinationNode.addIncomingEdge(this);
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#hashCode()
     */
    public int hashCode() {
        return (int) (id);
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public boolean equals(Object o) {
        return (o instanceof GraphEdge ? this.id == ((GraphEdge) o).id : false);
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#toString()
     */
    public String toString() {
        return "<Edge " + id + ": " + sourceNode + "->" + destinationNode + ">";
    }
}
